home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / xvisrc.zip / SCREEN.C < prev    next >
C/C++ Source or Header  |  1992-07-28  |  33KB  |  1,420 lines

  1. /* Copyright (c) 1990,1991,1992 Chris and John Downey */
  2. #ifndef lint
  3. static char *sccsid = "@(#)screen.c    2.3 (Chris & John Downey) 9/4/92";
  4. #endif
  5.  
  6. /***
  7.  
  8. * program name:
  9.     xvi
  10. * function:
  11.     PD version of UNIX "vi" editor, with extensions.
  12. * module name:
  13.     screen.c
  14. * module function:
  15.     Screen handling functions.
  16. * history:
  17.     STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  18.     Originally by Tim Thompson (twitch!tjt)
  19.     Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  20.     Heavily modified by Chris & John Downey
  21.  
  22. ***/
  23.  
  24. #include "xvi.h"
  25.  
  26. /*
  27.  * Size of command buffer - we won't allow anything more
  28.  * to be typed when we get to this limit.
  29.  */
  30. #define    CMDSZ    80
  31.  
  32. /*
  33.  * The following is used to optimise screen updating; we
  34.  * keep a record of the real screen state and compare it
  35.  * with the new version before actually doing any updating.
  36.  *
  37.  * The l_line part is guaranteed to be always null-terminated.
  38.  */
  39. typedef    struct    line_struct    {
  40.     char        *l_line;    /* storage for characters in line */
  41.     int            l_used;        /* number of bytes actually used */
  42.     unsigned int    l_flags;    /* information bits */
  43. } Sline;
  44.  
  45. /*
  46.  * Bit definitions for l_flags.
  47.  */
  48. #define    L_TEXT        0x01        /* is an ordinary text line */
  49. #define    L_MARKER    0x02        /* is a marker line ('@' or '~') */
  50. #define    L_DIRTY        0x04        /* has been modified */
  51. #define    L_MESSAGE    0x08        /* is a message line */
  52. #define    L_COMMAND    0x10        /* is a command line */
  53. #define    L_READONLY    0x20        /* message line for readonly buffer */
  54.  
  55. #define    L_STATUS    (L_MESSAGE | L_COMMAND)        /* is a status line */
  56.  
  57. static    Sline    *new_screen;        /* screen being updated */
  58. static    Sline    *real_screen;        /* state of real screen */
  59.  
  60. /*
  61.  * Status line glitch handling.
  62.  *
  63.  * Some terminals leave a space when changing colour. The number of spaces
  64.  * left is returned by the v_colour_cost() method within the VirtScr, and
  65.  * stored in the colour_cost variable herein - this is not perfect, it should
  66.  * really be in the Xviwin structure, but what the hell.
  67.  *
  68.  * "st_spare_cols" is the number of columns which are not used at the
  69.  * end of the status line; this is to prevent wrapping on this line,
  70.  * as this can do strange things to some terminals.
  71.  */
  72.  
  73. static    int    colour_cost = 0;
  74. static    int    st_spare_cols = 1;
  75.  
  76. static    int    line_to_new P((Xviwin *, Line *, int, long));
  77. static    void    file_to_new P((Xviwin *));
  78. static    void    new_to_screen P((VirtScr *, int, int));
  79. static    void    do_sline P((Xviwin *));
  80. static    void    clrline P((int));
  81.  
  82. /*
  83.  * This routine must be called to set up the screen memory -
  84.  * if it is not, we will probably get a core dump.
  85.  *
  86.  * Note that, at the moment, it must be called with a whole-screen
  87.  * window, i.e. the first window, and only that window, so that the
  88.  * nrows and ncols fields represent the whole screen.
  89.  */
  90. /*ARGSUSED*/
  91. void
  92. init_screen(win)
  93. Xviwin    *win;
  94. {
  95.     static char        *real_area, *new_area;
  96.     register int    count;
  97.     VirtScr        *vs;
  98.  
  99.     vs = win->w_vs;
  100.  
  101.     colour_cost = VScolour_cost(vs);
  102.     st_spare_cols = 1 + (colour_cost * 2);
  103.  
  104.     /*
  105.      * If we're changing the size of the screen, free the old stuff.
  106.      */
  107.     if (real_screen != NULL) {
  108.     free((char *) real_screen);
  109.     free((char *) new_screen);
  110.     free(real_area);
  111.     free(new_area);
  112.     }
  113.  
  114.     /*
  115.      * Allocate space for the lines, and for the structure holding
  116.      * information about each line. Notice that we allocate an
  117.      * extra byte at the end of each line for null termination.
  118.      */
  119.     real_screen = (Sline *) malloc((unsigned) VSrows(vs) * sizeof(Sline));
  120.     new_screen = (Sline *) malloc((unsigned) VSrows(vs) * sizeof(Sline));
  121.     real_area = malloc((unsigned) VSrows(vs) * (VScols(vs) + 1));
  122.     new_area = malloc((unsigned) VSrows(vs) * (VScols(vs) + 1));
  123.  
  124.     if (real_screen == NULL || new_screen == NULL ||
  125.     real_area == NULL || new_area == NULL) {
  126.     /* What to do now? */
  127.     sys_exit(0);
  128.     }
  129.  
  130.     /*
  131.      * Now assign all the rows ...
  132.      */
  133.     for (count = 0; count < VSrows(vs); count++) {
  134.     register Sline    *rp, *np;
  135.     register int    offset;
  136.  
  137.     rp = &real_screen[count];
  138.     np = &new_screen[count];
  139.  
  140.     offset = count * (VScols(vs) + 1);
  141.  
  142.     rp->l_line = real_area + offset;
  143.     np->l_line = new_area + offset;
  144.     rp->l_line[0] = np->l_line[0] = '\0';
  145.     rp->l_used = np->l_used = 0;
  146.     rp->l_flags = np->l_flags = 0;
  147.     }
  148. }
  149.  
  150. /*
  151.  * Set the L_DIRTY bit for a given line in both real_screen &
  152.  * new_screen if the stored representations are in fact different:
  153.  * otherwise clear it.
  154.  */
  155. static void
  156. mark_dirty(row)
  157.     int        row;
  158. {
  159.     Sline    *rp;
  160.     Sline    *np;
  161.     int        used;
  162.  
  163.     rp = &real_screen[row];
  164.     np = &new_screen[row];
  165.     if (
  166.  
  167.     (rp->l_flags & ~L_DIRTY) != (np->l_flags & ~L_DIRTY)
  168.     ||
  169.     (used = rp->l_used) != np->l_used
  170.     ||
  171.     strncmp(rp->l_line, np->l_line, used) != 0
  172.     ) {
  173.     /*
  174.      * The lines are different.
  175.      */
  176.     np->l_flags |= L_DIRTY;
  177.     rp->l_flags |= L_DIRTY;
  178.     } else {
  179.     rp->l_flags = (np->l_flags &= ~L_DIRTY);
  180.     }
  181. }
  182.  
  183. /*
  184.  * Transfer the specified window line into the "new" screen array, at
  185.  * the given row. Returns the number of screen lines taken up by the
  186.  * logical buffer line lp, or 0 if the line would not fit; this happens
  187.  * with longlines at the end of the screen. In this case, the lines
  188.  * which could not be displayed will have been marked with an '@'.
  189.  */
  190. static int
  191. line_to_new(window, lp, start_row, line)
  192. Xviwin        *window;
  193. Line        *lp;
  194. int        start_row;
  195. long        line;
  196. {
  197.     register unsigned    c;    /* next character from file */
  198.     register Sline    *curr_line;    /* output line - used for efficiency */
  199.     register char    *ltext;        /* pointer to text of line */
  200.     register int    curr_index;    /* current index in line */
  201.     bool_t        eoln;        /* true when line is done */
  202.     char        extra[MAX_TABSTOP];
  203.                     /* Stack for extra characters. */
  204.     int            nextra = 0;    /* index into stack */
  205.     int            srow, scol;    /* current screen row and column */
  206.     int            vcol;        /* virtual column */
  207.  
  208.     ltext = lp->l_text;
  209.     srow = start_row;
  210.     scol = vcol = 0;
  211.     curr_line = &new_screen[srow];
  212.     curr_index = 0;
  213.     eoln = FALSE;
  214.  
  215.     if (Pb(P_number)) {
  216.     static Flexbuf    ftmp;
  217.  
  218.     flexclear(&ftmp);
  219.     (void) lformat(&ftmp, NUM_FMT, line);
  220.     (void) strcpy(curr_line->l_line, flexgetstr(&ftmp));
  221.     scol += NUM_SIZE;
  222.     }
  223.  
  224.     while (!eoln) {
  225.     /*
  226.      * Get the next character to put on the screen.
  227.      */
  228.  
  229.     /*
  230.      * "extra" is a stack containing any extra characters
  231.      * we have to put on the screen - this is for chars
  232.      * which have a multi-character representation, and
  233.      * for the $ at end-of-line in list mode.
  234.      */
  235.  
  236.     if (nextra > 0) {
  237.         c = extra[--nextra];
  238.     } else {
  239.         unsigned    n;
  240.  
  241.         c = (unsigned char) (ltext[curr_index++]);
  242.  
  243.         /*
  244.          * Deal with situations where it is not
  245.          * appropriate just to copy characters
  246.          * straight onto the screen.
  247.          */
  248.         if (c == '\0') {
  249.  
  250.         if (Pb(P_list)) {
  251.             /*
  252.              * Have to show a '$' sign in list mode.
  253.              */
  254.             extra[nextra++] = '\0';
  255.             c = '$';
  256.         }
  257.  
  258.         } else {
  259.         char    *p;
  260.  
  261.         n = vischar((int) c, &p, vcol);
  262.         /*
  263.          * This is a bit paranoid assuming
  264.          * that Pn(P_tabstop) can never be
  265.          * greater than sizeof (extra), but
  266.          * so what.
  267.          */
  268.         if (nextra + n > sizeof extra)
  269.             n = (sizeof extra - nextra);
  270.         /*
  271.          * Stack the extra characters so that
  272.          * they appear in the right order.
  273.          */
  274.         while (n > 1) {
  275.             extra[nextra++] = p[--n];
  276.         }
  277.         c = p[0];
  278.         }
  279.     }
  280.  
  281.     if (c == '\0') {
  282.         /*
  283.          * End of line. Terminate it and finish.
  284.          */
  285.         eoln = TRUE;
  286.         curr_line->l_flags = L_TEXT;
  287.         curr_line->l_used = scol;
  288.         curr_line->l_line[scol] = '\0';
  289.         mark_dirty(srow);
  290.         break;
  291.     } else {
  292.         /*
  293.          * Sline folding.
  294.          */
  295.         if (scol >= window->w_ncols) {
  296.         curr_line->l_flags = L_TEXT;
  297.         curr_line->l_used = scol;
  298.         curr_line->l_line[scol] = '\0';
  299.         mark_dirty(srow);
  300.         srow += 1;
  301.         scol = 0;
  302.         curr_line = &new_screen[srow];
  303.         }
  304.  
  305.         if (srow >= window->w_cmdline) {
  306.         for (srow = start_row; srow < window->w_cmdline; srow++) {
  307.             curr_line = &new_screen[srow];
  308.  
  309.             curr_line->l_flags = L_MARKER;
  310.             curr_line->l_used = 1;
  311.             curr_line->l_line[0] = '@';
  312.             curr_line->l_line[1] = '\0';
  313.             mark_dirty(srow);
  314.         }
  315.         return(0);
  316.         }
  317.  
  318.         /*
  319.          * Store the character in new_scree